{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "本书配套视频课程：[解剖深度学习原理，从0实现深度学习库](https://ke.qq.com/course/2900371?tuin=ac5537fd) \n",
    "\n",
    "更多代码或学习资料将向购买视频课程或书的学生提供。\n",
    "\n",
    "\n",
    "+ 博客网站：[https://hwdong-net.github.io](https://hwdong-net.github.io)\n",
    "+ youtube频道: [hwdong](http://www.youtube.com/c/hwdong)\n",
    "+ bilibili网站：[hw-dong](https://space.bilibili.com/281453312)\n",
    "\n",
    "## numpy张量库\n",
    "\n",
    "\n",
    "### 1.2.2 创建ndarray对象\n",
    "\n",
    "#### array()函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1 3 2]\n",
      "(3,)\n",
      "[[1 3 2]\n",
      " [4 5 6]]\n",
      "(2, 3)\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "a= np.array([1,3,2])   #创建一维向量（张量）a\n",
    "print(a)\n",
    "print(a.shape)\n",
    "b= np.array([[1,3,2],[4,5,6]])   #创建二维向量（张量）b\n",
    "print(b)\n",
    "print(b.shape) #axis=0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "array()会根据传入的可迭代对象元素的类型创建相应元素类型的数组，也可以通过指定参数dtype创建相应数据元素类型的数组。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "int32\n",
      "[1 2 3 4]\n",
      "float64\n",
      "[1. 2. 3. 4.]\n"
     ]
    }
   ],
   "source": [
    "a = np.array([1,2,3,4])\n",
    "print(a.dtype)\n",
    "print(a)\n",
    "b = np.array([1,2,3,4], dtype=np.float64)\n",
    "print(b.dtype)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "ndarray的属性"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 (3,) 3 float64 8 <memory at 0x000001FB9BD45E80>\n",
      "2 (2, 3) 6 int32 4 <memory at 0x000001FB8D922790>\n"
     ]
    }
   ],
   "source": [
    "a= np.array([1.,2.,3.]) \n",
    "print(a.ndim,a.shape,a.size,a.dtype,a.itemsize,a.data)\n",
    "\n",
    "b= np.array([[1,2,3],[4,5,6]]) \n",
    "print(b.ndim,b.shape,b.size,b.dtype,b.itemsize,b.data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以通过下标访问多维数组的元素，称为**索引**，下标从0开始，例如访问b的第2行第3列元素，可以用下标[1,2]取访问："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3.0\n",
      "6\n"
     ]
    }
   ],
   "source": [
    "print(a[2])\n",
    "print(b[1,2])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "####  asarray()\n",
    "\n",
    "asarray()创建新的ndarray对象和传入的对象共享同一数据存储。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0 1 2 3 4]\n",
      "[1 2 3 4 5]\n",
      "<class 'numpy.ndarray'>\n",
      "[ 1  2 20  4  5]\n",
      "[ 1  2 20  4  5]\n"
     ]
    }
   ],
   "source": [
    "d= np.asarray(range(5)) \n",
    "print(d)\n",
    "e= np.asarray([1,2,3,4,5])     # 通过asarray也可以从一个序列或可迭代对象创建一个ndarray数组对象\n",
    "print(e)\n",
    "print(type(e))\n",
    "\n",
    "f= np.asarray(e)           #f和e共享同一个数据存储，修改一个就会影响另外一个\n",
    "e[2] = 20                  #可通过下标2访问e的第3个元素\n",
    "print(e)\n",
    "print(f)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### ndarray的tolist()方法\n",
    "\n",
    "将一个ndarray对象转变为一个python的list对象，如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'list'>\n",
      "[[1, 2, 3], [4, 5, 6]]\n"
     ]
    }
   ],
   "source": [
    "a = np.array([[1,2,3],[4,5,6]]) \n",
    "b = a.tolist()\n",
    "print(type(b))\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### astype()和reshape()\n",
    "\n",
    "ndarray的astype() 方法将一个ndarray对象的元素的数据类型转换成另外一种数据类型，"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "int32 float64\n",
      "[[100   2   3]\n",
      " [  4   5   6]]\n",
      "[[1. 2. 3.]\n",
      " [4. 5. 6.]]\n"
     ]
    }
   ],
   "source": [
    "c = a.astype(np.float64)   \n",
    "print(a.dtype,c.dtype)\n",
    "a[0][0] = 100\n",
    "print(a)\n",
    "print(c)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "numpy的reshape()函数或ndarray的reshape() 方法可通过改变ndarray对象的形状方法创建一个新的ndarray对象。如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0 1 2 3 4 5]\n",
      "[[0 1 2]\n",
      " [3 4 5]]\n",
      "[[0. 1. 2.]\n",
      " [3. 4. 5.]]\n"
     ]
    }
   ],
   "source": [
    "a= np.array(range(6)) \n",
    "b =np.reshape(a,(2,3)) \n",
    "c = a.reshape(2,3).astype(np.float64)\n",
    "print(a)\n",
    "print(b)\n",
    "print(c)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### arange()和linspace()\n",
    "\n",
    "arange()函数通过指定开始值、终值和步长创建表示等差数列的一维数组。\n",
    "```python\n",
    "numpy.arange([start], stop, [step], dtype=None)\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(np.arange(5))  #只指定end,start和step默认为0和1\n",
    "print(np.arange(2,5))\n",
    "print(np.arange(2,7,2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "和arange()类似，linspace()也用于创建一个初始值和终值之间的等差数列，只不过其第三个参数不是步长而是创建的元素的数目。\n",
    "\n",
    "numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)\n",
    "\n",
    "linspace()在start和stop之间创建num个数构成的等差数列。endpoint指示是否包含stop。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([2. , 2.2, 2.4, 2.6, 2.8])"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.linspace(2.0, 3.0, num=5, endpoint=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([2.  , 2.25, 2.5 , 2.75, 3.  ])"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.linspace(2.0, 3.0, num=5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "类似于linspace，logspace()创建一个等比数列。\n",
    "\n",
    "numpy.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None)\n",
    "\n",
    "logspace()先产生在start和stop之间的一个等差数列，再以base（base默认值为10）为底，以这些数作为指数，产生一个等比数列作为创建的numpy数组的元素。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 100.        ,  177.827941  ,  316.22776602,  562.34132519,\n",
       "       1000.        ])"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.logspace(2.0, 3.0, num=5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 9.        , 11.84466612, 15.58845727, 20.51556351, 27.        ])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.logspace(2.0, 3.0, base = 3,num=5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "####  full()、empty()、zeros()、ones()、eye()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[inf, inf, inf],\n",
       "       [inf, inf, inf]])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.full((2, 3),np.inf)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[3.5, 3.5, 3.5],\n",
       "       [3.5, 3.5, 3.5]])"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.full((2, 3),3.5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[3.5 3.5 3.5]\n",
      " [3.5 3.5 3.5]] \n",
      "\n",
      "[[0. 0. 0.]\n",
      " [0. 0. 0.]] \n",
      "\n",
      "[[1. 1.]] \n",
      "\n",
      "[[1. 0.]\n",
      " [0. 1.]] \n",
      "\n"
     ]
    }
   ],
   "source": [
    "print( np.empty((2,3)) ,'\\n')    # 创建形状为 (2,3)的二维数组，即相当于2*3的矩阵.元素的值未初始化\n",
    "print( np.zeros((2,3)) ,'\\n')   # 创建形状为 (2,3)元素值都是0的二维数组，即相当于2*3的矩阵\n",
    "print( np.ones((1,2)) ,'\\n' )   # 创建形状为 (1,2)元素值都是1的二维数组\n",
    "print(  np.eye(2)   ,'\\n' )     #创建形状为 (2,2)的单位矩阵，即对角线元素值为1，其他元素值都是0的矩阵"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "####  创建随机值张量的常用函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.37287844, 0.73462798, 0.2725476 ],\n",
       "       [0.09215323, 0.08142553, 0.39056221]])"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.random.rand(2,3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.78049868 0.59858685 0.40819972]\n",
      " [0.35385777 0.73980844 0.4145988 ]]\n"
     ]
    }
   ],
   "source": [
    "e = np.random.random((2,3))  # 创建形状为 (2,3)的元素值都是[0,1]之间的随机数的二维数组\n",
    "print(e)   "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a: [ 2.67015352  0.7075645  -2.75907281  0.86318258 -0.08484908]\n",
      "b: [[-1.13137719 -0.03767489  0.46301793]\n",
      " [-0.8753315   0.47252176 -0.71935943]]\n",
      "c: [ 0.21980379 -0.25845182  0.84023704 -0.68930176 -1.25869097]\n",
      "d: [[ 0.73014298  0.40774575 -0.19230705]\n",
      " [ 0.91937882 -0.18844764 -0.5762938 ]]\n",
      "e: [[1.59441259 1.51212102 2.54609328]\n",
      " [2.18860168 2.01901038 2.43592927]]\n",
      "(5,) (2, 3) (5,) (2, 3)\n"
     ]
    }
   ],
   "source": [
    "a = np.random.randn(5)        #生成5个服从(0,1)标准正态分布的随机数的一维数组\n",
    "b = np.random.randn(2,3)        #生成形状为(2,3)服从(0,1)标准正态分布的随机数的二维数组\n",
    "print(\"a:\",a)\n",
    "print(\"b:\",b)\n",
    "c = np.random.normal(0,1,5)        #生成5个服从(0,1)标准正态分布的随机数的一维数组\n",
    "d = np.random.normal(size=(2,3))   #生成size是(2,3）服从(0,1)标准正态分布的随机数的二维数组\n",
    "e = np.random.normal(2,0.3,size=(2,3))  #生成size是(2,3）服从(2,0.3)正态分布的随机数的二维数组\n",
    "print(\"c:\",c)\n",
    "print(\"d:\",d)\n",
    "print(\"e:\",e)\n",
    "\n",
    "print(a.shape,b.shape,c.shape,d.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以将一般的正态分布转化为标准正态分布$z\\backsim N(0,1)$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1.95872477 2.20936964 2.01858481]\n",
      " [2.04816291 1.48283688 1.84673311]]\n",
      "[[0.55591769 1.2117312  0.54753238]\n",
      " [0.31462126 0.76717955 0.3354586 ]]\n",
      "[[2.16677531 2.36351936 2.16425971]\n",
      " [2.09438638 2.23015386 2.10063758]]\n"
     ]
    }
   ],
   "source": [
    "mu, sigma = 2, 0.3\n",
    "e = np.random.normal(mu, sigma,size=(2,3)) \n",
    "print(e)\n",
    "f = np.random.randn(2,3) \n",
    "print(f)\n",
    "g = f*sigma+mu             # f= (g-mu)/sigma服从标准正太分布，g服从(mu,sigma)高斯分布\n",
    "print(g)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "random()函数有一个别名函数random_sample()，即两者是同一个函数，都生成[0,1]区间的均匀采样的随机数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[3.22317867, 6.75413051, 3.45074588],\n",
       "       [6.0667209 , 4.41510161, 6.63281013]])"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "5 * np.random.random_sample((2, 3)) +2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 添加、重复与铺设、合并与分裂、边缘填充、添加轴与交换轴\n",
    "\n",
    "nunmpy的**append()** 可以在已有数组后面添加内容创建一个新的数组，其函数规范是：\n",
    "```\n",
    "numpy.append(arr, values, axis=None)\n",
    "```\n",
    "表示在数组arr后面添加values的内容，axis表示沿着那个轴添加，默认为None，将创建一个摊平（扁平）的一维数组。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1 2 3]\n",
      "[1 2 3 4]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([1, 2, 3, 4, 5, 6, 7, 8, 9])"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array([1,2,3])\n",
    "b= np.append(a,4)\n",
    "print(a)\n",
    "print(b)\n",
    "np.append([1, 2, 3], [[4, 5, 6], [7, 8, 9]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2, 3],\n",
       "       [4, 5, 6],\n",
       "       [7, 8, 9]])"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.append([[1, 2, 3], [4, 5, 6]], [[7, 8, 9]], axis=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "重复函数**repeat()** 通过沿着某个轴重复数组中元素的方式创建一个新的ndarray数组。\n",
    "\n",
    "```numpy.repeat(a, repeats, axis=None)```\n",
    "\n",
    "创建一个新的数组，将a的元素沿着轴axis重复repeats次。axis默认值是None，表示创建一个摊平（扁平）的数组。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([3, 3, 3, 3])"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.repeat(3, 4)  #创建一个数组，将数值3重复4次"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1, 1, 2, 2, 3, 3, 4, 4])"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array([[1,2],[3,4]])\n",
    "np.repeat(a, 2)             #创建一个摊平的数组，即一维数组，其中元素是x中元素重复了2次"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2],\n",
       "       [1, 2],\n",
       "       [3, 4],\n",
       "       [3, 4]])"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.repeat(a, 2,axis=0)   "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 1, 2, 2],\n",
       "       [3, 3, 4, 4]])"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.repeat(a, 2,axis=1)   "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "铺设函数**tile(A, reps)** 可将整个数组像tile（瓷砖）一样的纵向或横向复制。\n",
    "```python\n",
    "numpy.tile(A, reps)\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1 2 3]\n",
      "[1 2 3 1 2 3]\n"
     ]
    }
   ],
   "source": [
    "a = np.array([1, 2,3])\n",
    "b= np.tile(a, 2)   #a重复2次的方式创建一个新的数组\n",
    "print(a)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "将数组a按形状(2, 2)方式铺设时，会先将a从一维张量[1, 2, 3]提成为二维张量[[1, 2, 3]]，再进行铺设："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2, 3, 1, 2, 3],\n",
       "       [1, 2, 3, 1, 2, 3]])"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.tile(a, (2, 2))   # a2行2列的方式平铺，创建一个新数组"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下面的c形状是(1，2)，而reps=2的长度为1，reps会先变为(1,2)，再进行铺设，即axis=0重复1次（即行方向上保持不变），而axis=2重复2次。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2]\n",
      " [3 4]]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([[1, 2, 1, 2],\n",
       "       [3, 4, 3, 4]])"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c = np.array([[1, 2], [3, 4]])\n",
    "print(c)\n",
    "np.tile(c, 2)  #reps会先变为(1,2)表示第1轴重复1次，第2轴重复2次"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2],\n",
       "       [3, 4],\n",
       "       [1, 2],\n",
       "       [3, 4]])"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.tile(c, (2, 1))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "拼接函数**concatenate()**沿着指定轴axis拼接多个数组，创建一个新的数组。\n",
    "```\n",
    "numpy.concatenate((a1, a2, …), axis=None, out=None)\n",
    "```\n",
    "\n",
    "axis指定合并方向的轴，默认值是0，如果是None，表示合并成一个扁平的数组，即一维数组。out默认为None，如果不是None，则合并结果将放到out里。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[5]\n",
      " [6]]\n",
      "[[1 2]\n",
      " [3 4]\n",
      " [5 6]]\n",
      "[[1 2 5]\n",
      " [3 4 6]]\n",
      "[1 2 3 4 5 6]\n"
     ]
    }
   ],
   "source": [
    "a = np.array([[1, 2], [3, 4]])\n",
    "b = np.array([[5, 6]])\n",
    "print(b.T)\n",
    "c = np.concatenate((a, b), axis=0)         #沿axis=0轴进行合并\n",
    "d = np.concatenate((a, b.T), axis=1)       #沿axis=1轴进行合并\n",
    "e = np.concatenate((a, b), axis=None)      #合并成一个扁平的数组\n",
    "print(c)\n",
    "print(d)\n",
    "print(e)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "叠加函数**stack**(arrays, axis=0, out=None)将一系列数组沿着axis的方向堆积（合并）成一个新的数组，axis值默认为0，表示第一个轴。如果axis=-1表示最后的轴。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2],\n",
       "       [3, 4],\n",
       "       [5, 6]])"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array([1, 2])\n",
    "b = np.array([3, 4])\n",
    "c = np.array([5, 6])\n",
    "np.stack((a, b,c))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 3, 5],\n",
       "       [2, 4, 6]])"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.stack((a,b,c),axis=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "作为stack()的特殊情形，numpy.column_stack(tup) 将tup中的一系列一维数组作为二维数组的列创建一个二维数组。如下面代码将2个一维数组作为新数组的列："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 4],\n",
       "       [2, 5],\n",
       "       [3, 6]])"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array((1,2,3))\n",
    "b = np.array((4,5,6))\n",
    "np.column_stack((a,b))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "作为concatenate()的特殊情形，**numpy.hstack(tup)** 沿着第2个轴（axis=1）进行拼接，或者说沿着水平方向（列）进行拼接。如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(3, 1) (3, 1)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([[1, 4],\n",
       "       [2, 5],\n",
       "       [3, 6]])"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array([[1],[2],[3]])       #3行1列\n",
    "b = np.array([[4],[5],[6]])       #3行1列\n",
    "print(a.shape,b.shape)\n",
    "np.hstack((a,b))                  #合并3行2列"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对一维数组的合并，仍然是一个一维数组："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(3,) (3,)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([1, 2, 3, 4, 5, 6])"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array((1,2,3))      \n",
    "b = np.array((4,5,6))\n",
    "print(a.shape,b.shape)\n",
    "np.hstack((a,b))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "作为concatenate()的特殊情形，**numpy.vstack(tup)** 沿着第1个轴（axis=0）进行拼接，或者说沿着垂直方向（行）进行拼接。如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1, 3)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([[1, 2, 3],\n",
       "       [4, 5, 6]])"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array([[1, 2, 3]])   #1行3列\n",
    "b = np.array([[4, 5, 6]])   #1行3列\n",
    "print(a.shape)\n",
    "np.vstack((a,b))            #合并为2行3列"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1],\n",
       "       [2],\n",
       "       [3],\n",
       "       [4],\n",
       "       [5],\n",
       "       [6]])"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c = np.array([[1], [2], [3]])   #有3行\n",
    "d = np.array([[4], [5], [6]])   #有3行\n",
    "np.vstack((c,d))                #合并为6行"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "vstack()对于一维数组(N,)会看成(1,N)的形状进行拼接。如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2, 3],\n",
       "       [4, 5, 6]])"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array([1, 2, 3])\n",
    "b = np.array([4, 5, 6])\n",
    "np.vstack((a,b))   # 1D数组a形状是(3,)会被看成(1,3)的2D数组，b也同样如此"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**分裂**是和合并相反的操作，函数**split()**沿着axis对数组进行分裂（axis默认值为0）\n",
    "```\n",
    "numpy.split(ary, indices_or_sections, axis=0)\n",
    "```\n",
    "indices_or_sections如果是整数N，表示分裂成N个相等的子数组，如果不可能做到，则失败。indices_or_sections如果是排序的整数数组，表示在轴方向上分裂的位置。如```indices_or_sections = [2,3]```、axis=0，其分裂的结果是：\n",
    "- ```ary[:2]```\n",
    "- ```ary[2:3]```\n",
    "- ```ary[3:]```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0. 1. 2. 3. 4. 5. 6. 7. 8.]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[array([0., 1., 2.]), array([3., 4., 5.]), array([6., 7., 8.])]"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.arange(9.0)\n",
    "print(x)\n",
    "np.split(x, 3)   #分裂成3个长度相等的子数组"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0. 1. 2. 3. 4. 5. 6. 7.]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[array([0., 1., 2.]),\n",
       " array([3., 4.]),\n",
       " array([5.]),\n",
       " array([6., 7.]),\n",
       " array([], dtype=float64)]"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.arange(8.0)\n",
    "print(x)\n",
    "np.split(x, [3, 5, 6, 10]) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "hsplit()、vsplit()分别是对应合并操作hstack()、vstack()的分裂函数，分别沿水平（axis=1）和垂直方向（axis=0）对数组分裂。这2个分裂函数都是分裂函数split()的特殊情形。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 0.  1.  2.  3.]\n",
      " [ 4.  5.  6.  7.]\n",
      " [ 8.  9. 10. 11.]\n",
      " [12. 13. 14. 15.]]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[array([[ 0.,  1.],\n",
       "        [ 4.,  5.],\n",
       "        [ 8.,  9.],\n",
       "        [12., 13.]]),\n",
       " array([[ 2.,  3.],\n",
       "        [ 6.,  7.],\n",
       "        [10., 11.],\n",
       "        [14., 15.]])]"
      ]
     },
     "execution_count": 48,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.arange(16.0).reshape(4, 4)\n",
    "print(x)\n",
    "np.hsplit(x, 2)                 #沿水平方向（列方向）分裂成2个相等的子数组"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[array([[0., 1., 2., 3.],\n",
       "        [4., 5., 6., 7.]]),\n",
       " array([[ 8.,  9., 10., 11.],\n",
       "        [12., 13., 14., 15.]])]"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.vsplit(x, 2)             #沿垂直方向（行方向）分裂成2个相等的子数组"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "np.pad()函数可以对数组的每一轴（维）进行边缘填充，即在每一轴（维）的前后边缘位置填充一些数值。\n",
    "```\n",
    "numpy.pad(array, pad_width, mode='constant', **kwargs)\n",
    "```\n",
    "arrar是输入数组，pad_width表示填充的宽度（元素的个数），而mode表示填充的方式，'constant'表示填充的常量，constant_values表示常量的值。如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[7, 8, 9]\n",
      "[4 4 7 8 9 6 6 6]\n"
     ]
    }
   ],
   "source": [
    "a = [7,8 ,9 ]\n",
    "b =np.pad(a, (2, 3), mode='constant', constant_values=(4, 6))\n",
    "print(a)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([7, 7, 7, 8, 9, 9, 9, 9])"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.pad(a, (2, 3), 'edge')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "mode='minimum'表示用数组中的最小值填充。对于多维数组，必须指定每一维的首尾填充的宽度。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[2, 5], [7, 9]]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([[2, 2, 2, 5, 2, 2, 2],\n",
       "       [2, 2, 2, 5, 2, 2, 2],\n",
       "       [7, 7, 7, 9, 7, 7, 7],\n",
       "       [2, 2, 2, 5, 2, 2, 2],\n",
       "       [2, 2, 2, 5, 2, 2, 2]])"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = [[2, 5], [7, 9]]\n",
    "print(a)\n",
    "np.pad(a, ((1, 2), (2, 3)), 'minimum')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**numpy.expand_dims(a, axis)** 在轴axis位置插入一个新轴，从而扩展了数组的形状。如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(2,)\n",
      "[3 5]\n",
      "(1, 2)\n",
      "[[3 5]]\n"
     ]
    }
   ],
   "source": [
    "x = np.array([3,5])                  #x是一维数组，只有1个轴\n",
    "print(x.shape)\n",
    "print(x)\n",
    "y = np.expand_dims(x, axis=0)           #y是二维数组，有2个轴，新增加的是轴axis=0，即新增加的轴成为第一个轴（行）\n",
    "print(y.shape)\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "也可以用np.newaxis给x添加一个轴，如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1, 2)\n",
      "[[3 5]]\n"
     ]
    }
   ],
   "source": [
    "y = x[np.newaxis,:]\n",
    "print(y.shape)\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(2, 1)\n",
      "[[3]\n",
      " [5]]\n"
     ]
    }
   ],
   "source": [
    "y = x[:,np.newaxis]\n",
    "print(y.shape)\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "时需要交换数组的轴，例如读取彩色图像时，其颜色通道可能是第3轴（axis=2），但在一些程序中，颜色通道需要在第一轴。有几个不同的函数可用于交换数组的轴。\n",
    "\n",
    "**numpy.swapaxes(a, axis1, axis2)**交换轴axis1和axis2。如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(2, 3, 4, 5)\n",
      "(4, 3, 2, 5)\n"
     ]
    }
   ],
   "source": [
    "A = np.random.random((2,3,4,5))\n",
    "print(A.shape)\n",
    "B = np.swapaxes(A,0,2)  #交换axos=0和axis=2的轴\n",
    "print(B.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**numpy.rollaxis(a, axis, start=0)**将轴axis向后滚动，直到位于轴start前面。如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(4, 2, 3, 5)\n",
      "(4, 3, 2, 5)\n"
     ]
    }
   ],
   "source": [
    "C = np.rollaxis(A,2,0)  # 将A的axis=2轴移动到axis=0轴前面，即C形状为：(4,23,,5)  \n",
    "print(C.shape) \n",
    "D = np.rollaxis(C,2,1)  #将C的axis=2轴移动到axis=1轴前面，即D形状为(4,3,2,5)\n",
    "print(D.shape) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**numpy.moveaxis(a, source, destination)**将轴source移到轴destination位置。如:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(4, 2, 3, 5)\n",
      "(4, 3, 2, 5)\n"
     ]
    }
   ],
   "source": [
    "C = np.moveaxis(A,2,0)  #A (2,3,4,5) C形状为(4,2,3,5)\n",
    "print(C.shape) \n",
    "D = np.rollaxis(C,2,1)  #D形状为(4,3,2,5)\n",
    "print(D.shape) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**numpy.transpose(a, axes=None)** 根据axes中的轴的次序对数组的轴进行重新排列。axes默认值为None，表示对轴逆序排列。这是一个更加通用灵活的函数。如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.5792545  0.59593983 0.66129472 0.38074224]\n",
      " [0.6356957  0.30193382 0.39393863 0.86570722]]\n",
      "[[0.5792545  0.6356957 ]\n",
      " [0.59593983 0.30193382]\n",
      " [0.66129472 0.39393863]\n",
      " [0.38074224 0.86570722]]\n",
      "(3, 2, 5, 4)\n"
     ]
    }
   ],
   "source": [
    "A = np.random.random((2,4))\n",
    "print(A)\n",
    "B = np.transpose(A)\n",
    "print(B)\n",
    "C = np.random.random((2,4,3,5))\n",
    "D = np.transpose(C,(2,0,3,1))\n",
    "print(D.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.2.3  ndarry数组的索引和切片\n",
    "\n",
    "numpy的索引（indexing）和切片（slicing）功能和python对序列对象的索引和切片是一样的，就是通过方括号```[]```指定元素下标的方式提取数组的一个子数组（元素）。\n",
    "\n",
    "和python不同的是，numpy数组的索引和切片不是创建一个新的数组，而是原数组的一个视图（视窗），即切片的子数组就是原数组的一部分，因此，通过这个这个切片的引用变量去修改这个切片，实际修改的就是原数组。如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 2 3\n",
      "[5 2 3 4 5]\n",
      "[2 3 4]\n",
      "[40  3  4]\n",
      "[ 5 40  3  4  5]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "a = np.array([1,2,3,4,5])   # 创建秩是1的数组，即一维数组\n",
    "print(a[0], a[1], a[2])   # 通过下标[]访问数组a的元素，打印它们，输出：1 2 3\n",
    "a[0] = 5                  # 修改下标0的元素a[0]的值\n",
    "print(a)                  # 打印整个数组，输出：5, 2, 3\n",
    "b  = a[1:4]               # a[1:4]返回下标1开始，直到下标4（不包含下标4）的元素构成的数组的切片\n",
    "print(b) \n",
    "b[0] = 40                 #切片b是a的一部分，修改b就是修改a中的元素\n",
    "print(b) \n",
    "print(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "索引和切片对多维数组是一样的，即可以对任意维进行索引或切片。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1  2  3  4]\n",
      " [ 5  6  7  8]\n",
      " [ 9 10 11 12]]\n",
      "10\n",
      "[ 9 10 11 12]\n",
      "[ 2  6 10]\n"
     ]
    }
   ],
   "source": [
    "a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])\n",
    "print(a)\n",
    "print(a[2,1])\n",
    "print(a[2])\n",
    "print(a[:,1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "也可以用负整数进行切片，如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1  2  3  4]\n",
      " [ 5  6  7  8]\n",
      " [ 9 10 11 12]]\n",
      "[[4 3 2]\n",
      " [8 7 6]]\n"
     ]
    }
   ],
   "source": [
    "a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])\n",
    "b = a[:2, -1:-4:-1]    # 切片区域是：第一维从0到2（不包含2），第2维从-1到-4，步长是-1，不包含-4。\n",
    "print(a)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "某一维的索引或切片如果用```:```表示这一维的所有元素，如果指定范围```start:end:step```未指定步长step，则默认step=1，如果维指定start则默认为-，如果未指定end，则默认是这一维的最后位置+1。如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2 3 4]\n",
      " [5 6 7 8]]\n",
      "[ 6 10]\n"
     ]
    }
   ],
   "source": [
    "c = a[:2,:]   #第一维默认end位置是2即第3行，而起始位置是0；第二维默认所有下标\n",
    "print(c)\n",
    "d = a[1:,1]   #第一维默认end位置是4，而起始位置是1；第二维是索引1.最后得到的是一个一维数组\n",
    "print(d)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "改变数组本身或切片，都使两者发生了改变，因为切片的数据就是原数组的一部分，即切片使原数组的一个窗口。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[  1   2   3 100]\n",
      " [  5   6   7   8]\n",
      " [  9  10  11  12]]\n",
      "[[100   3   2]\n",
      " [  8   7   6]]\n"
     ]
    }
   ],
   "source": [
    "a[0,3]=100\n",
    "print(a)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "一个三维张量（数组）的索引例子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[[ 0  1  2]\n",
      "  [ 3  4  5]\n",
      "  [ 6  7  8]]\n",
      "\n",
      " [[ 9 10 11]\n",
      "  [12 13 14]\n",
      "  [15 16 17]]\n",
      "\n",
      " [[18 19 20]\n",
      "  [21 22 23]\n",
      "  [24 25 26]]]\n"
     ]
    }
   ],
   "source": [
    "a = np.array(range(27)).reshape(3,3,3)\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[15 16 17]\n"
     ]
    }
   ],
   "source": [
    "print(a[1, 2])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1 4 7]\n"
     ]
    }
   ],
   "source": [
    "print(a[0,:,1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 5 14 23]\n"
     ]
    }
   ],
   "source": [
    "print(a[:,1,2])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**整型数组索引**(Integer array indexing)\n",
    "\n",
    "索引时，也可以给每一维索引传递不连续整数值。即给每一维传递的是一个整数数组。整型数组索引使得可以构建一个新的数组。如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1  2  3  4]\n",
      " [ 5  6  7  8]\n",
      " [ 9 10 11 12]]\n",
      "[ 2 12]\n",
      "[[ 1  2  3  4]\n",
      " [ 5  6  7  8]\n",
      " [ 9 10 11 12]]\n",
      "[111  12]\n"
     ]
    }
   ],
   "source": [
    "a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])\n",
    "c = a[[0,2],[1,3]]  #第1行（0）、3行（2）和第2列、4列的元素\n",
    "print(a)\n",
    "print(c)\n",
    "c[0] = 111\n",
    "print(a)\n",
    "print(c)       #说明c是独立于a的新的数组"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**布尔型数组索引(Boolean array indexing)** \n",
    "\n",
    "布尔型数组索引(Boolean array indexing)用于选取数组中满足某些条件的元素，例如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[False False]\n",
      " [ True  True]\n",
      " [ True  True]]\n",
      "[3 4 5 6]\n",
      "[3 4 5 6]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "a = np.array([[1,2], [3, 4], [5, 6]])\n",
    "\n",
    "bool_idx = (a > 2)   # 返回一个和a形状一样的值是True、False的数组\n",
    "print(bool_idx)      # Prints \"[[False False]\n",
    "                     #          [ True True]\n",
    "                     #          [ True True]]\"\n",
    "\n",
    "print(a[bool_idx])   # 根据布尔值是True和False元素\n",
    "print(a[a > 2])      #可以将上述两式合为一式"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.2.4 张量的计算\n",
    "\n",
    "#### 1. 逐元素计算\n",
    "\n",
    "前面已经看到对2个多维数组可以执行“逐元素”的```+、-、*、/、%```等运算，产生一个新的数组。如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 8 10 12]\n",
      " [14 16 18]]\n",
      "[[ 7 16 27]\n",
      " [40 55 72]]\n",
      "[[0 0 0]\n",
      " [2 1 0]]\n"
     ]
    }
   ],
   "source": [
    "a = np.array([[1,2,3],[4,5,6]])\n",
    "b = np.array([[7,8,9],[10,11,12]])\n",
    "print(a+b)\n",
    "print(a*b)\n",
    "print(b%a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这些运算符还有对应的numpy函数，如add()、subtract()、multiply()、divide()是对应```+、-、*、/```运算符的函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 8 10 12]\n",
      " [14 16 18]]\n",
      "[[-6 -6 -6]\n",
      " [-6 -6 -6]]\n",
      "[[ 7 16 27]\n",
      " [40 55 72]]\n",
      "[[0.14285714 0.25       0.33333333]\n",
      " [0.4        0.45454545 0.5       ]]\n"
     ]
    }
   ],
   "source": [
    "print(np.add(a,b))\n",
    "print(np.subtract(a,b))\n",
    "print(np.multiply(a,b))\n",
    "print(np.divide(a,b))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "numpy的函数都可以执行逐元素的计算，即对每个元素执行相应的运算，产生一个新的数组，如numpy的sqrt()、sin()、power()函数分别计算数组元素的平方根、正弦值、指数函数值："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1.         1.41421356 1.73205081]\n",
      " [2.         2.23606798 2.44948974]]\n",
      "[[ 0.84147098  0.90929743  0.14112001]\n",
      " [-0.7568025  -0.95892427 -0.2794155 ]]\n",
      "[[ 1  4  9]\n",
      " [16 25 36]]\n"
     ]
    }
   ],
   "source": [
    "print(np.sqrt(a))\n",
    "print(np.sin(a))\n",
    "print(np.power(a,2))   # 计算a的2次方"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "逐元素乘积也称为**Hadamard乘积**或**Schur 乘积**。\n",
    "\n",
    "#### 2. 累积计算\n",
    "\n",
    "可用numpy的函数或ndarry类的方法对ndarry对象执行累积型计算，如求和（sum()）、求最值（min()、max()）、均值（mean()）、标准差（std()）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "6 6\n",
      "1 1\n",
      "21 21\n",
      "3.5 3.5\n",
      "1.707825127659933 1.707825127659933\n"
     ]
    }
   ],
   "source": [
    "a = np.array([[1,2,3],[4,5,6]]) \n",
    "print(np.max(a),a.max())\n",
    "print(np.min(a),a.min())\n",
    "print(np.sum(a),a.sum())\n",
    "print(np.mean(a),a.mean())\n",
    "print(np.std(a),a.std())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这些函数还可以指定沿着数组的哪一个轴进行运算，如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2 3]\n",
      " [4 5 6]]\n",
      "[4 5 6] [3 6]\n",
      "[1 2 3] [1 4]\n",
      "[5 7 9] [ 6 15]\n",
      "[2.5 3.5 4.5] [2.5 3.5 4.5]\n",
      "[1.5 1.5 1.5] [1.5 1.5 1.5]\n"
     ]
    }
   ],
   "source": [
    "print(a)\n",
    "print(np.max(a,axis=0),a.max(axis=1))  # np.max(a,axis=0)表示沿着第0轴（第1维）的方向求最大值\n",
    "print(np.min(a,axis=0),a.min(axis=1))\n",
    "print(np.sum(a,axis=0),a.sum(axis=1))\n",
    "print(np.mean(a,axis=0),a.mean(axis=0))\n",
    "print(np.std(a,axis=0),a.std(axis=0))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3.  点积\n",
    "\n",
    "Hadamard乘积是逐元素的乘积，而张量的点积是**向量点积**和**矩阵乘积**的推广。\n",
    "\n",
    "```\n",
    "numpy.dot(a, b, out=None)\n",
    "```\n",
    "如果指定输出out，则结果输出到out里。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a*b: [ 2 15]\n",
      "dot(a,b): 17\n"
     ]
    }
   ],
   "source": [
    "a= np.array([1,3]) \n",
    "b= np.array([2,5]) \n",
    "print(\"a*b:\",a*b)\n",
    "print(\"dot(a,b):\",np.dot(a,b))         #两个向量的点积是一个数值（标量）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "矩阵和向量的相乘需要注意其对应轴的元素个数是否一致，如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a.shape: (2, 3)\n",
      "b.shape: (2,)\n",
      "c.shape: (3,)\n",
      "dot(b,a): [22 29 36]\n",
      "dot(a,c): [21 51]\n"
     ]
    }
   ],
   "source": [
    "a= np.array([[1,2,3],[4,5,6]]) \n",
    "b =  np.array([2,5]) \n",
    "c =  np.array([2,5,3]) \n",
    "print(\"a.shape:\",a.shape)\n",
    "print(\"b.shape:\",b.shape)\n",
    "print(\"c.shape:\",c.shape)\n",
    "#print(\"dot(a,b):\",np.dot(a,b))\n",
    "print(\"dot(b,a):\",np.dot(b,a))\n",
    "print(\"dot(a,c):\",np.dot(a,c))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于一维向量和二维矩阵，matmul()函数和运算符@也是执行矩阵乘法运算，和np.dot()具有相同作用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "dot(a,b): 17\n",
      "matmul(a,b): 17\n",
      "a@b: 17\n",
      "a.shape: (2, 3)\n",
      "b.shape: (3, 2)\n",
      "dot(a,b): [[16 26]\n",
      " [37 65]]\n",
      "matmul(a,b): [[16 26]\n",
      " [37 65]]\n",
      "a@b: [[16 26]\n",
      " [37 65]]\n"
     ]
    }
   ],
   "source": [
    "a= np.array([1,3]) \n",
    "b= np.array([2,5]) \n",
    "print(\"dot(a,b):\",np.dot(a,b))\n",
    "print(\"matmul(a,b):\",np.matmul(a,b))\n",
    "print(\"a@b:\",a@b)\n",
    "\n",
    "a= np.array([[1,2,3],[4,5,6]]) \n",
    "b= np.array([[2,5],[1,3],[4,5]]) \n",
    "print(\"a.shape:\",a.shape)          # 2*3矩阵\n",
    "print(\"b.shape:\",b.shape)          # 3*2矩阵\n",
    "print(\"dot(a,b):\",np.dot(a,b))\n",
    "print(\"matmul(a,b):\",np.matmul(a,b))\n",
    "print(\"a@b:\",a@b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 4  广播Broadcasting\n",
    "\n",
    "广播是一个强有力的机制，使得numpy可以对不同形状的数组进行算术运算。例如前面用一个数和一个数组进行运算。相当于将这个数变成和数组一样大小的数组，然后进行逐元素的运算。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2]\n",
      " [3 4]]\n",
      "[[4 5]\n",
      " [6 7]]\n",
      "[[4 5]\n",
      " [6 7]]\n"
     ]
    }
   ],
   "source": [
    "a = np.array([[1,2],[3,4]]) \n",
    "print(a)\n",
    "\n",
    "print(a+3)\n",
    "print(a+ np.array([[3,3],[3,3]]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "一个数和一个张量的减法、乘法、除法等也是执行这种广播计算。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 3  6]\n",
      " [ 9 12]]\n",
      "[[0.33333333 0.66666667]\n",
      " [1.         1.33333333]]\n"
     ]
    }
   ],
   "source": [
    "print(a*3)\n",
    "print(a/3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "二维数组a可以和下面的一维数组b进行运算："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[2 4]\n",
      " [4 6]]\n"
     ]
    }
   ],
   "source": [
    "b = np.array([1,2]) \n",
    "print(a+b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1]\n",
      " [2]\n",
      " [3]]\n",
      "[4 5]\n",
      "[[5 6]\n",
      " [6 7]\n",
      " [7 8]]\n"
     ]
    }
   ],
   "source": [
    "a = np.array([[1],[2],[3]])   #a是(3,1)的二维数组\n",
    "b = np.array([4,5])           #b是(2,)数组的一维数组\n",
    "print(a)\n",
    "print(b)\n",
    "print(a+b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
